package ldk.learning.nio

import java.net.InetSocketAddress
import java.nio.ByteBuffer
import java.nio.channels.SelectionKey
import java.nio.channels.Selector
import java.nio.channels.ServerSocketChannel
import java.nio.channels.SocketChannel
import java.util.concurrent.Executors

/**
 * 一个简单的Echo Server服务器
 */
class EchoServer {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            val echoServer = EchoServer()
            println("EchoServer启动中....")
            echoServer.nioEchoServer()
        }
    }

    fun nioEchoServer(){
        val selector = Selector.open()
        val serverSocketChannel = ServerSocketChannel.open()
        serverSocketChannel.configureBlocking(false)
        val serverSocketChannelSelectionKey = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT)
        serverSocketChannel.socket().bind(InetSocketAddress(6666))
        val executorServices = Executors.newCachedThreadPool()
        println("EchoServer启动完成: NIO模式")
        while(true){
            selector.select()
            if (serverSocketChannelSelectionKey.isAcceptable){
                val socketChannel = serverSocketChannel.accept()
                if (socketChannel != null){
                    socketChannel.configureBlocking(false)
                    socketChannel.register(selector, SelectionKey.OP_READ)
                }
            }
            selector.keys().forEach {
                if (it != serverSocketChannelSelectionKey && it.isReadable){
                    val channel = it.channel() as SocketChannel
                    executorServices.execute {
                        echoSocketChannel(channel)
                        channel.close()
                    }
                    it.cancel()
                }
            }
        }
    }

    fun bioEchoServer(){
        val serverSocketChannel = ServerSocketChannel.open()
        serverSocketChannel.socket().bind(InetSocketAddress(6666))
        println("EchoServer启动完成, BIO模式")
        val executorServices = Executors.newCachedThreadPool();
        while (true){
            val socketChannel = serverSocketChannel.accept()
            executorServices.execute {
                println("socketChannel is $socketChannel")
                echoSocketChannel(socketChannel)
                socketChannel.close()
            }
        }
    }

    private fun echoSocketChannel(socketChannel: SocketChannel){
        val buffer = ByteBuffer.allocate(512)
        val bytesRead = socketChannel.read(buffer)
        if (bytesRead == -1){
            println("byteRead is -1, socketChannel closed: $socketChannel")
            return
        }

        if (!buffer.hasRemaining()){
            println("buffer 没有剩余的空间了")
        }
        // 这里表示耗时操作
        Thread.sleep(3000)
        val message = String(buffer.array(), 0, bytesRead)
        println("接受到消息: $message， 开始进行回显")
        buffer.clear()
        val toByteArray = message.toByteArray()
        buffer.put(toByteArray)
        buffer.flip()
        while (buffer.hasRemaining()){
            socketChannel.write(buffer)
        }
    }
}